/* 
    scroll-view 处理下拉刷新与触底加载
    王欢
    2020/1/15
    ## 注意
        默认阈值为 45
        如果自定义插槽存在  则为插槽的高度
        默认滚动方向为 y轴
        插槽自定义样式可根据  sv_scroll_xy  sv_refresher_code 自定义
    ### 需求自由配置  记得设置 scroll view 高度
    ### vant tabs demo
    
    <van-tabs 
        sticky="{{ true }}"
        active="{{ sv_tabsIndex }}" 
        swipeable="{{ true }}" 
        animated="{{ true }}" 
        bind:change="sv_tabsChange" 
        data-refresh_auto="{{ true }}" 
        class="__van-tabsCover"
    >
        <van-tab 
            wx:for="{{ sv_tabsInfo }}" 
            wx:key="index" 
            title="{{ item.title }}" 
            data-index="{{ index }}"
        >
            <scroll-view 
                class="van-tab__scrollView"
                scroll-y="{{ sv_direction === 'y' }}"
                refresher-enabled="{{ sv_refresher_enabled }}"
                refresher-threshold="{{ sv_refresher_threshold }}"
                refresher-default-style="{{ sv_refresher_default_style }}"
                refresher-background="{{ sv_refresher_background }}"
                refresher-triggered="{{ sv_refresher_triggered }}"
                bindscrolltolower="sv_scrolltolower"
                bindrefresherpulling="sv_refresherpulling"
                bindrefresherrefresh="sv_refresherrefresh"
                bindrefresherrestore="sv_refresherrestore"
                bindrefresherabort="sv_refresherabort"

            >   
                <!-- 自定义插槽   必须设置一个固定高度  -->
                <view class="van-tab__scrollView_slot" 
                    slot="refresher" 
                    id="{{ sv_slot_id }}"
                >
                    {{ sv_refresher_notic }}
                </view>
                <!-- 列表视图   -->
                <view class="scroll-item" 
                    wx:for="{{ sv_tabsInfo[sv_tabsIndex].list }}"
                    wx:for-index="listItemIndex"
                    wx:key="listItemIndex"
                >item view</view>
                <!-- 提示   -->
                <block>
                    <view wx:if="{{ sv_tabsInfo[sv_tabsIndex].end }}">
                        <van-empty description="当前列表没有内容哦" wx:if="{{ !sv_tabsInfo[sv_tabsIndex].list.length }}" />
                        <block wx:else>
                            <van-divider wx:if="{{ sv_tabsEndNoticShow && sv_tabsInfo[sv_tabsIndex].count !== 1 }}" contentPosition="center">
                                {{ sv_tabsEndNoticText }}
                            </van-divider>
                        </block>
                    </view>
                    <van-loading size="24px" wx:if="{{ sv_tabsReachBottomLoading }}" class="__van-tabsLoading">
                        {{ sv_tabsReachBottomLoadingText }}
                    </van-loading>
                </block>
            </scroll-view>
        </van-tab>
    </van-tabs>
*/

/* 2021/8/2 
    新添 scroll-view item的居中滑动
    配置
        ##必要配置
         // scroll-view 元素 class 或 id
        sv_scrollClass:""
         //  scroll-view  子元素 class
        sv_scrollItemClass:""
        可选配置
            //自定义scroll-left 存储变量
        sv_scrollLeftModel

*/

const mixin_scrollToView = require("./mixin_scrollToView");
module.exports = {
    data: {
        /* ----------------  常用配置项 start  ---------------- */

        // tabs数据列表
        sv_tabsInfo: [{
            //标题
            title: "全部"
            // query type
            , type: 0
            // 页码
            , count: 1
            // 数据是否加载完
            , end: false
            // 数据列表
            , list: []
            /* 
            // 置顶数据
            , topList: []
            // 置顶数据合并 key
            , topKey: "" 
            */
        }]
        // tabs索引
        , sv_tabsIndex: 0
        // tabs http path
        , sv_tabsHttpPath: ""
        // 列表初次加载生命周期事件 - onLoad onShow custom自定义
        , sv_tabsInitLife: "custom"
        // tabs http query转换设置
        , sv_tabsHttpKeys: {
            type: "type"
            , count: "page"
            , sv_tabsPageLimit: "limit"
        }
        // tabs一页数据量
        , sv_tabsPageLimit: 10
        // 是否使用 vant tabs
        , sv_setVantAuto: false
        // 是否开启滑动切换
        , sv_openScrollToView: false
        // 是否开启  触底加载
        , sv_openReachBottom: true
        // 开启自定义下拉刷新
        , sv_refresher_enabled: false
        //scroll-view 元素 class 或 id
        , sv_scrollClass: ""
        // scroll-view  子元素 class
        , sv_scrollItemClass: ""
        // scroll-view scroll-left载入的model
        , sv_scrollLeftModel: "v_scrollLeft"
        // scroll-vew data  scrollleft -- model
        , sv_scrollLeft: ""
        /* ---------------- 常用配置项 end  ---------------- */
        // 切换tabs是否自动刷新
        , sv_tabsRefreshAuto: true
        // tabs 是否处于触底加载事件中
        , sv_tabsReachBottomLoading: false
        // tabs 当前页码加载完毕 提示
        , sv_tabsEndNoticText: "已经到底了哦"
        // tabs 当前页码加载完毕 提示是否显示
        , sv_tabsEndNoticShow: true
        // tabs 触底加载文本提示
        , sv_tabsReachBottomLoadingText: "loading..."
        // 滑动方向
        , sv_direction: "y"
        // 设置自定义下拉刷新阈值
        , sv_refresher_threshold: 45
        // 设置自定义下拉刷新默认样式
        , sv_refresher_default_style: "none"
        // 设置自定义下拉刷新区域背景颜色
        , sv_refresher_background: "#FFF"
        //  设置当前下拉刷新状态，true 表示下拉刷新已经被触发，false 表示下拉刷新未被触发
        , sv_refresher_triggered: false
        // 开启 scroll anchoring 特性，即控制滚动位置不随内容变化而抖动
        , sv_scroll_anchoring: true
        // 当前滑动的值
        , sv_scroll_xy: 0
        // 下拉刷新插槽 id
        , sv_slot_id: "scroll_refresher"
        // 下拉刷新提示文本
        , sv_refresher_notic: ""
        // 下拉刷新 复位 未达到阈值 提示文本
        , sv_refresher_notic_restore: "下拉刷新"
        //	下拉刷新 达到阈值 提示文本
        , sv_refresher_notic_refresh: "松手即可刷新"
        // 下拉刷新 http请求中 提示文本
        , sv_refresher_notic_httpBefore: "请求中"
        // 下拉刷新 http请求成功 提示文本
        , sv_refresher_notic_httpSuc: "刷新成功"
        // 下拉刷新 http请求失败 提示文本
        , sv_refresher_notic_httpFail: "刷新失败"
        // 下拉刷新  http请求完成 复位间隔时间
        , sv_refresher_restore_timeSplit: 500
        // 滑动状态码
        /* 
            0 复位
            1 未达到阈值
            2 达到阈值
            3 http请求中
            4 http请求成功
            5 http请求失败
        */
        , sv_refresher_code: 0
    }
    , mixins: [mixin_scrollToView]
    /* 
        ,computed:{
            // ## tabs http query 合并的参数
            sv_tabsHttpQueryAssignInfo(){
                return {};
            }
        } 
    */
    , onLoad() {
        this.sv_getTabsInitLife("onLoad");
    }
    , onShow() {
        this.sv_getTabsInitLife("onShow");
    }
    , onReady() {
        // 如果自定义插槽存在   获取插槽高度为阈值
        const page = this;
        const { sv_refresher_enabled, sv_slot_id } = page.data;
        if (sv_refresher_enabled) {
            if (sv_slot_id) {
                dd.createSelectorQuery()
                    .select('#' + sv_slot_id)
                    .boundingClientRect(res => {
                        if (res) {
                            page.setData({
                                sv_refresher_threshold: res.height
                            });
                        } else {
                            page.setData({
                                sv_refresher_enabled: false
                                , sv_refresher_default_style: "white"
                            });
                            console.warn(`scrollTabs Warn: invalid query ${sv_slot_id}`);
                        }

                    }).exec();
            } else {
                page.$fail("scrollTabs Error: missing params sv_slot_id")
            }
        }
    }

    /* ----------------  必须配置项 start  ---------------- */
    /* 
        自定义处理当前列表参数  每个项目可根据接口单独设置
        list  列表
        end   列表是否加载结束
        传入的值 
            res 接口返回值
            tabsItem    sv_tabsInfo[sv_tabsIndex] 当前索引对象
            concatAuto  是否拼接  true 拼接 false 赋值
        返回一个新的 当前索引对象
        
    */
    , sv_updateTabsItem({
        res
        , tabsItem
        , concatAuto
    }) {
        const page = this;
        //前后台定义 一页数据量
        const { data } = res;
        const { sv_tabsPageLimit } = page.data;
        tabsItem.end = data.length < sv_tabsPageLimit;
        /* 
            //通过接口返回  总页数
            const { data: { total, list:data } } = res;
            const { count } = tabsItem;
            tabsItem.end = total == 0 || count == total;;
        
        */
        if (concatAuto) {
            tabsItem.list = tabsItem.list.concat(data);
        } else {
            tabsItem.list = data;
        }
        return tabsItem;
    }
    /* ----------------  必须配置项 end  ---------------- */

    /* 
        // 对 tabsInfo data 进行处理
        ,sv_tabsDataTransform( tabsData ){} 
    */
    // scroll view 触底或者触右加载
    , sv_scrolltolower() {
        const page = this;
        const { sv_openReachBottom } = page.data;
        if (sv_openReachBottom) {
            page.sv_tabsReachBottom();
        }
    }
    // scroll view 自定义下拉刷新控件被下拉	
    , sv_refresherpulling(event) {
        const page = this;
        const { sv_refresher_threshold
            , sv_refresher_notic_refresh
            , sv_refresher_notic_restore } = page.data;
        const { dy } = event.detail;


        let code;
        let notic;
        if (dy < sv_refresher_threshold) {
            code = 1;
            notic = sv_refresher_notic_restore;
        } else {
            code = 2;
            notic = sv_refresher_notic_refresh;

        }
        page.setData({
            sv_refresher_code: code
            , sv_scroll_xy: dy
            , sv_refresher_notic: notic
        });
    }
    // scroll view 自定义下拉刷新被触发	
    , sv_refresherrefresh() {
        const page = this;
        const { sv_refresher_notic_httpBefore
            , sv_refresher_notic_httpSuc
            , sv_refresher_notic_httpFail
            , sv_refresher_restore_timeSplit
        } = page.data;
        page.setData({
            sv_refresher_notic: sv_refresher_notic_httpBefore
            , sv_refresher_code: 3
        });
        function callbackCpt({ notic, code, err }) {
            page.setData({
                sv_refresher_code: code
                , sv_refresher_notic: notic
            });

            setTimeout(function () {
                page.setData({
                    sv_refresher_notic: notic
                    , sv_refresher_triggered: false
                });
            }, sv_refresher_restore_timeSplit);
            if (err) {
                page.$fail(err);
            }
        }
        page.sv_tabsPullDownRefresh({
            success() {
                callbackCpt({
                    notic: sv_refresher_notic_httpSuc
                    , code: 4
                });
            }
            , fail(err) {
                callbackCpt({
                    notic: sv_refresher_notic_httpFail
                    , code: 5
                    , err
                });
            }
        })
    }
    // scroll view 自定义下拉刷新被中止	
    , sv_refresherabort(event) {
        this.sv_refresherrestore();
    }
    // scroll view 自定义下拉刷新被复位	
    , sv_refresherrestore() {
        const page = this;
        const { sv_refresher_notic_restore } = page.data;
        page.setData({
            sv_refresher_code: 0
            , sv_scroll_xy: 0
            , sv_refresher_notic: sv_refresher_notic_restore
            , sv_refresher_triggered: false
        });
    }
    // 置顶数据筛选
    , sv_topMerge(navItem) {
        // 置顶数据拼接
        const { topList, topKey, list } = navItem;
        if (topList && topList.length) {
            if (topKey && list.length) {
                const { list } = navItem;

                for (let i = list.length - 1; i >= 0; i--) {
                    let listItem = list[i];
                    let hasTop = topList.some(item => {
                        return item[topKey] == listItem[topKey];
                    })

                    if (hasTop) {
                        list.splice(i, 1);
                    }
                }
            }

            navItem.list.unshift(...topList);
        }
        return navItem;
    }
    // 初次加载
    , sv_getTabsInitLife(lifeName) {
        const page = this;
        const { sv_tabsRefreshAuto, sv_tabsIndex, sv_tabsInitLife } = page.data;
        if (sv_tabsInitLife && sv_tabsInitLife === lifeName) {

            page.sv_tabsChange(undefined, {
                tabs_index: sv_tabsIndex
                , refresh_auto: sv_tabsRefreshAuto
            });
        }
    }
    //加载分页内容
    , sv_getTabsPage(params) {
        const page = this;
        const { sv_tabsHttpKeys
            , sv_tabsHttpQueryAssignInfo
            , sv_tabsHttpPath
        } = page.data;
        const httpQuerys = {};
        Object.keys(sv_tabsHttpKeys)
            .forEach(key => {
                const transKey = sv_tabsHttpKeys[key];
                if (transKey) {
                    httpQuerys[transKey] = params[key];
                }
            });
        if (sv_tabsHttpQueryAssignInfo) {
            Object.assign(httpQuerys, sv_tabsHttpQueryAssignInfo);
        }
        // 搜索关键字
        const { searchKeys } = params;
        if (searchKeys) {
            Object.assign(httpQuerys, searchKeys);
        }
        return page.$get(sv_tabsHttpPath, httpQuerys);
    }
    //导航切换
    , sv_tabsChange(event, navInfo) {
        const page = this;
        const { sv_tabsInfo, sv_tabsPageLimit, sv_tabsRefreshAuto, sv_setVantAuto } = page.data;
        if (!sv_tabsInfo.length) {
            throw Error("scrollTabs Error: tabsInfo length is null");
        }
        let sv_tabsIndex;
        let refreshAuto = sv_tabsRefreshAuto;
        let success;
        let fail;
        // 搜索关键字  Object 类型 
        let searchKeys;
        if (event) {
            let index;
            const eventDataset = event.currentTarget.dataset;
            if (sv_setVantAuto) {
                index = event.detail.index;
            } else {
                index = eventDataset.tabs_index;
            }
            sv_tabsIndex = index;
            searchKeys = eventDataset.search_keys;
            if ("refresh_auto" in eventDataset) {
                refreshAuto = eventDataset.refresh_auto;
            }
        } else if (navInfo) {
            sv_tabsIndex = navInfo.tabs_index;
            searchKeys = navInfo.search_keys;
            success = navInfo.success;
            fail = navInfo.fail;
            if ("refresh_auto" in navInfo) {
                refreshAuto = navInfo.refresh_auto;
            }
        } else {
            throw ReferenceError("scrollTabs Error: tabsChange missing required parameter")
        }
        page.setData({
            sv_tabsIndex
        });
        /* 是否滑动切换 */
        const { sv_openScrollToView } = page.data;
        // 前提不使用 vant组件
        if (!sv_setVantAuto && sv_openScrollToView) {
            const { sv_scrollClass, sv_scrollItemClass, sv_scrollLeftModel } = page.data;
            page.scrollIntoView({
                scrollClass: sv_scrollClass
                , scrollItemClass: sv_scrollItemClass
                , scrollIndex: sv_tabsIndex
                , scrollLeftModel: sv_scrollLeftModel
            });
        }
        let navItem = sv_tabsInfo[sv_tabsIndex];

        // 切换加载  条件
        // 强制刷新开启
        //  或者   没有加载完  并且  数据为0
        if (refreshAuto || (
            !navItem.end
            &&
            !navItem.list.length
        )) {
            if (refreshAuto) {
                navItem.count = 1;
            }
            const { type, count } = navItem;

            page.sv_getTabsPage({
                type
                , count
                , sv_tabsPageLimit
                , searchKeys
            })
                .then(res => {
                    const { sv_tabsDataTransform } = page;
                    // 处理当前列表 数据
                    if (sv_tabsDataTransform && typeof sv_tabsDataTransform === "function") {
                        list = sv_tabsDataTransform(list);
                    }
                    // 处理当前列表数据  是否结束   列表数据赋值
                    navItem = page.sv_updateTabsItem({ tabsItem: navItem, res, concatAuto: false });
                    // 处理当前列表  置顶数据   
                    navItem = page.sv_topMerge(navItem);
                    page.setData({
                        sv_tabsInfo
                    });
                    if (success && typeof success === "function") {
                        success();
                    }

                }).catch(err => {
                    if (fail && typeof fail === "function") {
                        fail(err);
                    } else {
                        page.$fail(err);
                    }
                });
        }



    }
    // tabs 下拉刷新
    , sv_tabsPullDownRefresh({ success, fail }) {
        const page = this;
        const { sv_tabsIndex } = page.data;
        page.sv_tabsChange(undefined, {
            tabs_index: sv_tabsIndex
            , refresh_auto: true
            , success
            , fail
        });
    }
    // tabs 触底加载
    , sv_tabsReachBottom() {
        const page = this;
        let { sv_tabsInfo, sv_tabsIndex, sv_tabsPageLimit, sv_tabsReachBottomLoading } = page.data;
        if (!sv_tabsInfo.length) {
            throw Error("scrollTabs Error: tabsInfo length is null");
        }
        let navItem = sv_tabsInfo[sv_tabsIndex];
        const { count, end, type } = navItem;
        // 如果处于触底加载事件中  退出
        if (sv_tabsReachBottomLoading) {
            return false;
        }
        if (end) {
            return false;
        } else {
            sv_tabsReachBottomLoading = true;
            page.setData({
                sv_tabsReachBottomLoading
            });
            const nextcount = count + 1;
            page.sv_getTabsPage({
                type
                , count: nextcount
                , sv_tabsPageLimit
            }).then(res => {
                // 处理当前列表数据  是否结束   列表数据赋值
                navItem = page.sv_updateTabsItem({ tabsItem: navItem, res, concatAuto: true });
                navItem.count = nextcount;
                sv_tabsReachBottomLoading = false;
                // navItem = page.sv_topMerge( navItem );
                page.setData({
                    sv_tabsInfo
                    , sv_tabsReachBottomLoading
                });
            }).catch(err => {
                sv_tabsReachBottomLoading = false;
                page.setData({
                    sv_tabsReachBottomLoading
                });
                page.$fail(err);
            });
        }
    }

}